import os
import sys
import argparse
import xml.etree.ElementTree as ET
import pandas as pd
import subprocess
import json
import shutil

# --- 配置区 ---

# 默认的 manifest 文件相对路径
MANIFEST_FILE_PATH = ".repo/manifests/default.xml"

# 输出的 Excel 文件名
OUTPUT_FILE_NAME = "aosp_code_stats_cloc.xlsx"

# --- 核心功能函数 ---

def check_cloc_installed():
    """检查系统中是否安装了 cloc 命令"""
    if shutil.which("cloc") is None:
        print("错误: 'cloc' 命令未找到。")
        print("请先安装 cloc 工具。您可以访问 https://github.com/AlDanial/cloc 获取安装指南。")
        print("例如，在 Ubuntu/Debian 上运行: sudo apt-get install cloc")
        sys.exit(1)
    print("'cloc' 工具已找到，准备开始分析。")

def parse_manifest(aosp_root):
    """解析 aosp manifest 文件，提取所有 project 的 path 属性"""
    manifest_path = os.path.join(aosp_root, MANIFEST_FILE_PATH)
    print(f"正在解析 Manifest 文件: {manifest_path}")

    if not os.path.exists(manifest_path):
        print(f"错误: Manifest 文件未找到 at '{manifest_path}'")
        print("请确保输入的路径是 AOSP 源代码的根目录。")
        sys.exit(1)

    try:
        tree = ET.parse(manifest_path)
        root = tree.getroot()
        projects = [p.get('path') for p in root.findall('.//project') if p.get('path')]
        print(f"成功解析 Manifest，找到 {len(projects)} 个仓库。")
        return projects
    except ET.ParseError as e:
        print(f"错误: 解析 XML 文件失败: {e}")
        sys.exit(1)

def analyze_repo_with_cloc(repo_full_path):
    """
    使用 cloc 分析单个仓库，返回 (代码总量, 代码 NBNC 总量)。
    代码总量 = blank + comment + code
    代码 NBNC 总量 = code
    """
    if not os.path.isdir(repo_full_path):
        return None  # 仓库目录不存在

    # 构建 cloc 命令
    # --json: 输出为 JSON 格式，方便解析
    # --quiet: 隐藏进度信息，只输出最终结果
    command = ["cloc", "--json", "--quiet", repo_full_path]

    try:
        # 执行命令并捕获输出
        result = subprocess.run(
            command,
            capture_output=True,
            text=True, # 将 stdout 和 stderr 解码为文本
            check=False # 如果 cloc 返回非零退出码，不抛出异常
        )

        if result.returncode != 0:
            # 如果 cloc 出错（例如，目录中没有可识别的文件），则 stderr 会有信息
            # 这种情况我们视为代码量为0
            # print(f"  [信息] cloc 在处理 {repo_full_path} 时返回非零代码: {result.stderr.strip()}")
            return 0, 0

        # 解析 JSON 输出
        cloc_data = json.loads(result.stdout)

        # 提取 'SUM' 部分的数据，这是所有语言的汇总
        summary = cloc_data.get("SUM", {})
        
        # 'code' 字段就是 NBNC (Non-Blank, Non-Comment) 代码量
        nbnc_lines = summary.get("code", 0)
        blank_lines = summary.get("blank", 0)
        comment_lines = summary.get("comment", 0)

        # 总代码量是三者之和
        total_lines = nbnc_lines + blank_lines + comment_lines
        
        return total_lines, nbnc_lines

    except FileNotFoundError:
        # 这个异常理论上不会触发，因为我们在开头已经检查过了
        print("错误: 'cloc' 命令未找到。请确保它已安装并在系统 PATH 中。")
        sys.exit(1)
    except json.JSONDecodeError:
        print(f"  [警告] 解析 cloc 的 JSON 输出失败，仓库: {repo_full_path}")
        return 0, 0
    except Exception as e:
        print(f"  [错误] 在分析仓库 {repo_full_path} 时发生未知错误: {e}")
        return 0, 0

def save_to_excel(results, output_file):
    """将统计结果保存到 Excel 文件"""
    if not results:
        print("没有可供保存的结果。")
        return
        
    print(f"\n正在将结果保存到 {output_file} ...")
    try:
        df = pd.DataFrame(results, columns=['仓库路径', '代码总量', '代码 NBNC 总量'])
        df.to_excel(output_file, index=False, engine='openpyxl')
        print(f"保存成功！文件路径: {os.path.abspath(output_file)}")
    except Exception as e:
        print(f"\n错误: 保存 Excel 文件失败: {e}")
        print("请检查您是否拥有当前目录的写入权限，或者文件是否已被其他程序打开。")

def main():
    """主函数，负责整体流程控制"""
    parser = argparse.ArgumentParser(
        description="使用 cloc 统计 AOSP 项目中各个仓库的代码量。"
    )
    parser.add_argument("aosp_path", help="AOSP 源代码的根目录路径。")
    args = parser.parse_args()

    # 1. 检查 cloc 是否安装
    check_cloc_installed()

    aosp_root = os.path.abspath(args.aosp_path)
    if not os.path.isdir(aosp_root):
        print(f"错误: 提供的路径 '{aosp_root}' 不是一个有效的目录。")
        sys.exit(1)

    # 2. 解析 manifest 获取仓库列表
    repo_paths = parse_manifest(aosp_root)
    
    results = []
    total_repos = len(repo_paths)

    print("\n开始使用 cloc 分析各个仓库的代码量 (这可能需要一些时间)...")
    for i, repo_path in enumerate(repo_paths, 1):
        full_path = os.path.join(aosp_root, repo_path)
        
        # 打印进度
        print(f"[{i}/{total_repos}] 正在分析: {repo_path}")

        stats = analyze_repo_with_cloc(full_path)
        
        if stats is None:
            print(f"  [警告] 仓库路径不存在，已跳过: {full_path}")
            continue

        total_lines, nbnc_lines = stats
        results.append({
            '仓库路径': repo_path,
            '代码总量': total_lines,
            '代码 NBNC 总量': nbnc_lines
        })
        print(f"  -> 完成: 总行数={total_lines}, NBNC行数={nbnc_lines}")

    # 4. 保存结果到 Excel
    save_to_excel(results, OUTPUT_FILE_NAME)

if __name__ == "__main__":
    main()
